/*!
\copyright  Copyright (c) 2023 - 2024 Qualcomm Technologies International, Ltd.\n
            All Rights Reserved.\n
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\brief      Implementation of the Version Sharing Profile.
*/

#ifdef INCLUDE_CROSS_VERSION_DFU
#include "dfu_version_share_profile.h"
#include "dfu_version_share_profile_private.h"
#include "dfu_version_share_profile_l2cap.h"

#include "multidevice.h"

#include <bredr_scan_manager.h>
#include <connection_manager.h>
#include <upgrade.h>
#include <upgrade_peer.h>
#include <bt_device.h>
#include <stdlib.h>
#include <logging.h>
#include <message.h>
#include <panic.h>

#define DEBUG_LOG_MODULE_NAME dfu_version_share

/*! Emperically decided timeout for disconnection of profile. */
#define DFU_VERSION_SHARE_PROFILE_L2CAP_TIMEOUT_TIME 5000

/*! Timeout for connection of ACL Link from tws_topology_defaults.h */
#define DFU_VERSION_SHARE_PROFILE_ACL_TIMEOUT_TIME 11000

/*! Emperically decided Timeout for connection of ACL, L2CAP channel creation and data sharing */
#define DFU_VERSION_SHARE_PROFILE_GLOBAL_TIMEOUT_TIME 20000

/*
@startuml DFU Version Share Data Flow

participant Left_EB #lightGreen
participant Right_EB #Red

Left_EB --> Right_EB : L2CAP Connect
Left_EB -> Right_EB : DFU Version Data Sharing
Right_EB -> Right_EB : Compare With Self Version and Send Response to Application
Right_EB -> Left_EB : DFU Version Data Sharing
Left_EB -> Left_EB : Compare With Self Version and Send Response to Application
Left_EB --> Right_EB : L2CAP Dsiconnect

@enduml
*/

/*! \brief Structure holding data for the dfu_version_share_profile module */
typedef struct
{

    /*! Client task */
    Task client_task;

    /*! DFU Version Share Profile connected status */
    bool dfu_version_share_profile_connected:1;

    /*! DFU Version Share Profile L2CAP channel sink */
    Sink dfu_version_share_profile_l2cap_sink;

    /*! DFU Version Share Profile Tx data pointer. */
    uint8* dfu_version_tx_data_ptr;

    /*! DFU Version Share Profile Tx data length. */
    uint8 dfu_version_tx_data_length;

    /*! DFU Version Share Profile Rx data pointer. */
    uint8* dfu_version_rx_data_ptr;

    /*! DFU Version Share Profile Rx data length. */
    uint8 dfu_version_rx_data_length;

    dfu_version_share_profile_dfu_version_t self_dfu_version;

    dfu_version_share_profile_dfu_version_t peer_dfu_version;

    upgrade_cross_version_status_t dfu_version_comparison_result;

} dfu_version_share_profile_t;

static void dfuVersionShareProfile_VersionProfileTaskHandler(Task task, MessageId id, Message message);
static TaskData dfuversionShareDataVersionProfileTask = {dfuVersionShareProfile_VersionProfileTaskHandler};

static void dfuVersionShareProfile_SendDataToOtherEarbud(void);
static void dfuVersionShareProfile_ReceiveDataFromOtherEarbud(Message message);

static void dfuVersionShareProfile_FormulateDataForOtherEarbud(void);
static void dfuVersionShareProfile_ProcessDataFromOtherEarbud(void);

static void dfuVersionShareProfile_CompareDfuVersion(void);


dfu_version_share_profile_t dfu_version_share_profile =
{
    .client_task = NULL,
    .dfu_version_share_profile_connected = FALSE,
    .dfu_version_comparison_result = UPGRADE_CROSS_VERSION_UNKNOWN,
};

static void dfuVersionShareProfile_Reset(void)
{
    DEBUG_LOG_INFO("dfuVersionShareProfile_Reset");

    dfu_version_share_profile.dfu_version_share_profile_connected = FALSE;

    if(Multidevice_IsLeft())
    {
        BredrScanManager_PageScanRelease(&dfuversionShareDataVersionProfileTask);
        ConManagerUnregisterTpConnectionsObserver(cm_transport_bredr, &dfuversionShareDataVersionProfileTask);
    }
    else
    {
        bdaddr central_addr;
        /* release the ACL, now held open by L2CAP */
        DfuVersionShareProfile_DeviceGetCentralBdAddr(&central_addr);
        ConManagerReleaseAcl(&central_addr);
    }

}

static void dfuVersionShareProfile_VersionProfileTaskHandler(Task task, MessageId id, Message message)
{
    UNUSED(task);

    switch (id)
    {
        case CON_MANAGER_TP_CONNECT_IND:
            DEBUG_LOG_DEBUG("DfuVersionShareProfile ACL Connected");
            MessageCancelAll(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT_ACL);
            if (Multidevice_IsLeft())
            {   
                bdaddr peripheral_addr;
                DfuVersionShareProfile_DeviceGetPeripheralBdAddr(&peripheral_addr);

                if (!DfuVersionShareProfileL2cap_Connect(&peripheral_addr))
                {
                    DEBUG_LOG_WARN("DfuVersionShareProfileL2cap_Connect failed or already connected!");
                }

                DEBUG_LOG_INFO("DfuVersionShareProfile CONNECT L2CAP CENTRAL");
            }
        break;

        case CON_MANAGER_TP_DISCONNECT_IND:
            DEBUG_LOG_DEBUG("DfuVersionShareProfile ACL Disconnected");
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT:
        {
            DEBUG_LOG_DEBUG("DfuVersionShareProfile DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT");
            MessageCancelAll(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT);
            dfuVersionShareProfile_Reset();
            MessageSend(dfu_version_share_profile.client_task, DFU_VERSION_SHARE_PROFILE_ERROR, NULL);
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT_ACL:
        {
            DEBUG_LOG_DEBUG("DfuVersionShareProfile DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT_ACL");
            MessageCancelAll(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT_ACL);
            dfuVersionShareProfile_Reset();
            MessageSend(dfu_version_share_profile.client_task, DFU_VERSION_SHARE_PROFILE_ERROR, NULL);
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_CONNECTED:
        {
            DFU_VERSION_SHARE_PROFILE_CONNECTED_T *version_message = (DFU_VERSION_SHARE_PROFILE_CONNECTED_T *)message;
            PanicNull(version_message);

            DEBUG_LOG_DEBUG("DfuVersionShareProfile L2CAP Connect status:%d", version_message->status);

            if (version_message->status == dfu_version_share_profile_status_peer_connected)
            {
                dfu_version_share_profile.dfu_version_share_profile_connected = TRUE;
                dfu_version_share_profile.dfu_version_share_profile_l2cap_sink = version_message->sink;

                dfuVersionShareProfile_FormulateDataForOtherEarbud();

                /* Start sending data between the earbuds, only central is allowed to send first*/
                if (Multidevice_IsLeft())
                {
                    MessageSendLater(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_DISCONNECT, NULL, DFU_VERSION_SHARE_PROFILE_L2CAP_TIMEOUT_TIME);
                    MessageSend(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_SEND_DATA, NULL);
                }
            }
            else 
            {
                dfuVersionShareProfile_Reset();
                MessageSend(dfu_version_share_profile.client_task, DFU_VERSION_SHARE_PROFILE_ERROR, NULL);
            }
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_DISCONNECT:
        {
            if (Multidevice_IsLeft() && dfu_version_share_profile.dfu_version_share_profile_connected)
            {
                DEBUG_LOG_DEBUG("DfuVersionShareProfile DFU VERSION SHARE DISCONNECT");

                if (!DfuVersionShareProfileL2cap_Disconnect())
                {
                    DEBUG_LOG_WARN("DfuVersionShareProfile_L2cap_Disconnect failed or already disconnected!");
                }
            }
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_DISCONNECTED:
        {
            DEBUG_LOG_DEBUG("DfuVersionShareProfile L2CAP Disconnected");
            
            MessageCancelAll(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT);

            dfuVersionShareProfile_Reset();

            DFU_VERSION_SHARE_PROFILE_VERSION_COMPARISON_RESULT_T *comparison_result = 
                    (DFU_VERSION_SHARE_PROFILE_VERSION_COMPARISON_RESULT_T *)(malloc(sizeof(DFU_VERSION_SHARE_PROFILE_VERSION_COMPARISON_RESULT_T)));

            if (!comparison_result)
            {
                DEBUG_LOG_INFO("%s:Not enough memory to send dfu_version_comparison_result to client!");
                return;
            }
            comparison_result->dfu_version_comparison_result = dfu_version_share_profile.dfu_version_comparison_result;
            MessageSend(dfu_version_share_profile.client_task, (MessageId)DFU_VERSION_SHARE_PROFILE_COMPARISON_RESULT, (void *)comparison_result);
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_DATA_RECEIVED:
        {
            DEBUG_LOG_DEBUG("DfuVersionShareProfile Receiving Data");
            /* Handle timeout message for sending version data.*/
            if (dfu_version_share_profile.dfu_version_share_profile_connected)
            {
                /* Send data to other earbud over version profile. */
                dfuVersionShareProfile_ReceiveDataFromOtherEarbud(message);
            }
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_PROCESS_RECEIVED_DATA:
        {
            DEBUG_LOG_DEBUG("DfuVersionShareProfile Processing Received Data");
            /* Handle timeout message for sending version data.*/
            if (dfu_version_share_profile.dfu_version_share_profile_connected)
            {
                /* Send data to other earbud over version profile. */
                dfuVersionShareProfile_ProcessDataFromOtherEarbud();
            }
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_SEND_DATA:
        {
            DEBUG_LOG_DEBUG("DfuVersionShareProfile Sending Data");
            /* Handle timeout message for sending version data.*/
            if (dfu_version_share_profile.dfu_version_share_profile_connected)
            {
                /* Send data to other earbud over version profile. */
                dfuVersionShareProfile_SendDataToOtherEarbud();
            }
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_READY_TO_SEND:
        {
            if (dfu_version_share_profile.dfu_version_share_profile_connected)
            {
                DEBUG_LOG_DEBUG("DfuVersionShareProfile more data can be sent now");
            }
        }
        break;

        case DFU_VERSION_SHARE_PROFILE_INTERNAL_COMPARE_DFU_VERSION:
        {
            DEBUG_LOG_DEBUG("DfuVersionShareProfile Compare Version Data");
            if (dfu_version_share_profile.dfu_version_share_profile_connected)
            {
                /* Formulate for sending version data to peer earbud. */
                dfuVersionShareProfile_CompareDfuVersion();

                /* Only central is allowed to disconnect */
                if (Multidevice_IsLeft())
                {
                    MessageSend(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_DISCONNECT, NULL);
                }
                else /* Only peripheral is allowed to transmit now */
                {
                    MessageSend(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_SEND_DATA, NULL);
                }
            }
        }
        break;

        default:
        {
            DEBUG_LOG_DEBUG("Unhandled message:%d",  id);
        }
        break;
    }
}

static void dfuVersionShareProfile_FormulateDataForOtherEarbud(void)
{

    DEBUG_LOG_DEBUG("dfuVersionShareProfile_FormulateDataForOtherEarbud");

    if(UpgradeGetVersion(
                    &dfu_version_share_profile.self_dfu_version.major,
                    &dfu_version_share_profile.self_dfu_version.minor,
                    &dfu_version_share_profile.self_dfu_version.config))
    {
        dfu_version_share_profile.dfu_version_tx_data_length = sizeof(dfu_version_share_profile.self_dfu_version.major)
                                                            + sizeof(dfu_version_share_profile.self_dfu_version.minor)
                                                            + sizeof(dfu_version_share_profile.self_dfu_version.config);
        dfu_version_share_profile.dfu_version_tx_data_ptr = (uint8 *)PanicUnlessMalloc(dfu_version_share_profile.dfu_version_tx_data_length);

        memcpy(dfu_version_share_profile.dfu_version_tx_data_ptr,
                    (uint8*)&dfu_version_share_profile.self_dfu_version.major,
                    sizeof(dfu_version_share_profile.self_dfu_version.major));

        memcpy((dfu_version_share_profile.dfu_version_tx_data_ptr 
                    + sizeof(dfu_version_share_profile.self_dfu_version.major)),
                    (uint8*)&dfu_version_share_profile.self_dfu_version.minor,
                    sizeof(dfu_version_share_profile.self_dfu_version.minor));

        memcpy((dfu_version_share_profile.dfu_version_tx_data_ptr 
                    + sizeof(dfu_version_share_profile.self_dfu_version.major)
                    + sizeof(dfu_version_share_profile.self_dfu_version.minor)),
                    (uint8*)&dfu_version_share_profile.self_dfu_version.config,
                    sizeof(dfu_version_share_profile.self_dfu_version.config));

        DEBUG_LOG_INFO("dfuVersionShareProfile ready to send dfu_version_share_profile : %d : %d : %d ", 
                    *(uint16*)dfu_version_share_profile.dfu_version_tx_data_ptr,
                    *(uint16*)(dfu_version_share_profile.dfu_version_tx_data_ptr
                    + sizeof(dfu_version_share_profile.self_dfu_version.major)),
                    *(uint16*)(dfu_version_share_profile.dfu_version_tx_data_ptr
                    + sizeof(dfu_version_share_profile.self_dfu_version.major)
                    + sizeof(dfu_version_share_profile.self_dfu_version.minor)));

    }
    else
    {
        DEBUG_LOG_WARN("dfuVersionShareProfile_FormulateDataForOtherEarbud Failed");
    }

}

static void dfuVersionShareProfile_ProcessDataFromOtherEarbud(void)
{
    DEBUG_LOG_DEBUG("dfuVersionShareProfile_ProcessDataFromOtherEarbud");

    if(dfu_version_share_profile.dfu_version_rx_data_length == 
                    (sizeof(dfu_version_share_profile.peer_dfu_version.major)
                    + sizeof(dfu_version_share_profile.peer_dfu_version.minor)
                    + sizeof(dfu_version_share_profile.peer_dfu_version.config)))
    {
        memcpy((uint8*)&dfu_version_share_profile.peer_dfu_version.major,
                    dfu_version_share_profile.dfu_version_rx_data_ptr,
                    sizeof(dfu_version_share_profile.peer_dfu_version.major));

        memcpy((uint8*)&dfu_version_share_profile.peer_dfu_version.minor,
                    dfu_version_share_profile.dfu_version_rx_data_ptr
                    + sizeof(dfu_version_share_profile.peer_dfu_version.major),
                    sizeof(dfu_version_share_profile.peer_dfu_version.minor));

        memcpy((uint8*)&dfu_version_share_profile.peer_dfu_version.config,
                    dfu_version_share_profile.dfu_version_rx_data_ptr 
                    + sizeof(dfu_version_share_profile.peer_dfu_version.major)
                    + sizeof(dfu_version_share_profile.peer_dfu_version.minor),
                    sizeof(dfu_version_share_profile.peer_dfu_version.config));

        DEBUG_LOG_INFO("dfuVersionShareProfile received dfu_version_share_profile : %d : %d : %d ", 
                    dfu_version_share_profile.peer_dfu_version.major,
                    dfu_version_share_profile.peer_dfu_version.minor,
                    dfu_version_share_profile.peer_dfu_version.config);

        MessageSend(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_COMPARE_DFU_VERSION, NULL);

    }
    else
    {
        DEBUG_LOG_WARN("dfuVersionShareProfile_ProcessDataFromOtherEarbud Failed");
    }

}

static void dfuVersionShareProfile_CompareDfuVersion(void)
{
    DEBUG_LOG_INFO("dfuVersionShareProfile_CompareDfuVersion PEER dfu_version : %d : %d : %d ", 
                        dfu_version_share_profile.peer_dfu_version.major,
                        dfu_version_share_profile.peer_dfu_version.minor,
                        dfu_version_share_profile.peer_dfu_version.config);
    
    DEBUG_LOG_INFO("dfuVersionShareProfile_CompareDfuVersion SELF dfu_version : %d : %d : %d ", 
                        dfu_version_share_profile.self_dfu_version.major,
                        dfu_version_share_profile.self_dfu_version.minor,
                        dfu_version_share_profile.self_dfu_version.config);

    if(dfu_version_share_profile.self_dfu_version.major > dfu_version_share_profile.peer_dfu_version.major)
    {
        dfu_version_share_profile.dfu_version_comparison_result = UPGRADE_CROSS_VERSION_HIGHER;
    }
    else if(dfu_version_share_profile.self_dfu_version.major < dfu_version_share_profile.peer_dfu_version.major)
    {
        dfu_version_share_profile.dfu_version_comparison_result = UPGRADE_CROSS_VERSION_LOWER;
    }
    else
    {
        if(dfu_version_share_profile.self_dfu_version.minor > dfu_version_share_profile.peer_dfu_version.minor)
        {
            dfu_version_share_profile.dfu_version_comparison_result = UPGRADE_CROSS_VERSION_HIGHER;
        }
        else if(dfu_version_share_profile.self_dfu_version.minor < dfu_version_share_profile.peer_dfu_version.minor)
        {
            dfu_version_share_profile.dfu_version_comparison_result = UPGRADE_CROSS_VERSION_LOWER;
        }
        else
        {
            dfu_version_share_profile.dfu_version_comparison_result = UPGRADE_CROSS_VERSION_MATCHED;
        }
    }
    
    UpgradePeerSetPeerVersion(dfu_version_share_profile.peer_dfu_version.major, 
                            dfu_version_share_profile.peer_dfu_version.minor,
                            dfu_version_share_profile.peer_dfu_version.config);

    DEBUG_LOG_INFO("dfuVersionShareProfile dfu_version_comparison_result : %d", dfu_version_share_profile.dfu_version_comparison_result);
}


static void dfuVersionShareProfile_SendDataToOtherEarbud(void)
{

    DEBUG_LOG_DEBUG("dfuVersionShareProfile_SendDataToOtherEarbud");

    uint16 data_size = dfu_version_share_profile.dfu_version_tx_data_length + sizeof(dfu_version_share_profile.dfu_version_tx_data_length);

    /* Send the data to other earbud over the version profile L2CAP channel. */
    if (SinkIsValid(dfu_version_share_profile.dfu_version_share_profile_l2cap_sink))
    {
        /* Get the amount of available space left in the sink */
        uint16 sink_slack = SinkSlack(dfu_version_share_profile.dfu_version_share_profile_l2cap_sink);
    
        /* Make sure we have enough space for sending the data */
        if (sink_slack >= data_size)
        {
            SinkClaim(dfu_version_share_profile.dfu_version_share_profile_l2cap_sink, data_size);

            uint8 *base = SinkMap(dfu_version_share_profile.dfu_version_share_profile_l2cap_sink);

            /* Copy the data_length. */
            memcpy(base, (void *)&dfu_version_share_profile.dfu_version_tx_data_length, sizeof(dfu_version_share_profile.dfu_version_tx_data_length));
            base += sizeof(dfu_version_share_profile.dfu_version_tx_data_length);

            /* Copy the version data. */
            memcpy(base, (void *)dfu_version_share_profile.dfu_version_tx_data_ptr, dfu_version_share_profile.dfu_version_tx_data_length);

            DEBUG_LOG_DEBUG("dfuVersionShareProfile queued data_len:%d", dfu_version_share_profile.dfu_version_tx_data_length);

            /* Now send the data to other earbud over the version profile L2CAP channel. */
            if (!SinkFlush(dfu_version_share_profile.dfu_version_share_profile_l2cap_sink, data_size))
            {
                DEBUG_LOG_WARN("DFU Version Share profile SinkFlush FAILED");
            }

            /* Free the memory as the data is transmitted. */
            free(dfu_version_share_profile.dfu_version_tx_data_ptr);

            DEBUG_LOG_DEBUG("dfuVersionShareProfile data txed t = %10u ", SystemClockGetTimerTime());
        }
        else
        {
            DEBUG_LOG_WARN("Not enough sink slack to send data to other earbud");
        }
    }
    else
    {
        DEBUG_LOG_WARN("Invalid version_profile L2CAP sink");
    }

}

static void dfuVersionShareProfile_ReceiveDataFromOtherEarbud(Message message)
{

    DEBUG_LOG_DEBUG("dfuVersionShareProfile_ReceiveDataFromOtherEarbud");

    DFU_VERSION_SHARE_PROFILE_DATA_RECEIVED_T *data_rxed = (DFU_VERSION_SHARE_PROFILE_DATA_RECEIVED_T *)message;
    PanicNull(data_rxed);

    Source version_profile_source = data_rxed->source;
    const uint8 *source_map = SourceMap(version_profile_source);
    uint16 len = SourceBoundary(version_profile_source);

    /* First data is the data length. */
    memmove(&dfu_version_share_profile.dfu_version_rx_data_length, source_map, sizeof(dfu_version_share_profile.dfu_version_rx_data_length));
    source_map += sizeof(dfu_version_share_profile.dfu_version_rx_data_length);

    dfu_version_share_profile.dfu_version_rx_data_ptr = (uint8 *)PanicUnlessMalloc(dfu_version_share_profile.dfu_version_rx_data_length);

    /* Second data is the dfu_version_share_profile. */
    dfu_version_share_profile.dfu_version_rx_data_ptr = (uint8 *)PanicUnlessMalloc(dfu_version_share_profile.dfu_version_rx_data_length);
    memmove(dfu_version_share_profile.dfu_version_rx_data_ptr, source_map, dfu_version_share_profile.dfu_version_rx_data_length);

    DEBUG_LOG_DEBUG("dfuVersionShareProfile data rxed t = %10u ", SystemClockGetTimerTime());

    SourceDrop(version_profile_source, len);

    MessageSend(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_PROCESS_RECEIVED_DATA, NULL);
}

bool DfuVersionShareProfile_Init(Task init_task)
{
    DEBUG_LOG_INFO("DfuVersionShareProfile_Init");
    UNUSED(init_task);
    DfuVersionShareProfileL2cap_ManagerRegister(&dfuversionShareDataVersionProfileTask);
    return TRUE;
}

void DfuVersionShareProfile_GetVersion(Task client_task)
{

    bdaddr peripheral_addr;
    bdaddr central_addr;

    dfu_version_share_profile.client_task = client_task;

    DfuVersionShareProfile_DeviceGetPeripheralBdAddr(&peripheral_addr);
    DfuVersionShareProfile_DeviceGetCentralBdAddr(&central_addr);

    MessageSendLater(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT, NULL, DFU_VERSION_SHARE_PROFILE_GLOBAL_TIMEOUT_TIME);

    if (Multidevice_IsLeft())
    {
        BredrScanManager_PageScanRequest(&dfuversionShareDataVersionProfileTask, SCAN_MAN_PARAMS_TYPE_FAST);
        /* register to get notified of connection to peer and start timeout for the peripheral to establish the ACL */
        ConManagerRegisterTpConnectionsObserver(cm_transport_bredr, &dfuversionShareDataVersionProfileTask);
        MessageSendLater(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT_ACL, NULL, DFU_VERSION_SHARE_PROFILE_ACL_TIMEOUT_TIME);
        DEBUG_LOG_INFO("DfuVersionShareProfile_GetVersion CONNECT ACL");
    }
    else
    {
        uint16* connect_wait_lock = ConManagerCreateAcl(&central_addr);
        if(connect_wait_lock)
        {
            MessageSendLater(&dfuversionShareDataVersionProfileTask, DFU_VERSION_SHARE_PROFILE_INTERNAL_TIMEOUT_ACL, NULL, DFU_VERSION_SHARE_PROFILE_ACL_TIMEOUT_TIME);
        }
        else
        {
            DEBUG_LOG_WARN("DfuVersionShareProfile_GetVersion ACL already connected / failed");
            return;
        }
        DEBUG_LOG_INFO("DfuVersionShareProfile_GetVersion CONNECT ACL & L2CAP PERIPHERAL");
    }
}

bool DfuVersionShareProfile_DeviceGetCentralBdAddr(bdaddr* bd_addr)
{
    bdaddr self;
    bdaddr peer;

    if (appDeviceGetMyBdAddr(&self) && appDeviceGetPeerBdAddr(&peer))
    {
        if ( Multidevice_IsLeft() )
        {
            *bd_addr = self;
        }
        else
        {
            *bd_addr = peer;
        }
        return TRUE;
    }
    return FALSE;
}

bool DfuVersionShareProfile_DeviceGetPeripheralBdAddr(bdaddr* bd_addr)
{
    bdaddr self;
    bdaddr peer;

    if (appDeviceGetMyBdAddr(&self) && appDeviceGetPeerBdAddr(&peer))
    {
        if ( Multidevice_IsLeft() )
        {
            *bd_addr = peer;
        }
        else
        {
            *bd_addr = self;
        }
        return TRUE;
    }
    return FALSE;
}
#endif //#ifdef INCLUDE_CROSS_VERSION_DFU